package com.kvest.map.mapview.engine.model;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Pair;
import com.kvest.map.R;
import com.kvest.map.mapview.engine.utils.Utils;
import com.kvest.map.mapview.engine.network.ImageLoader;

import javax.microedition.khronos.opengles.GL10;
import java.lang.ref.WeakReference;
import java.util.LinkedList;

/**
 * Created with IntelliJ IDEA.
 * User: r.belokon
 * Date: 22.04.13
 * Time: 14:50
 * To change this template use File | Settings | File Templates.
 */
public class TileTextureManager implements BitmapLoadCallback {
    private static TileTextureManager instance;
    private static final Object lock = new Object();

    private LinkedList<Pair<WeakReference<TextureLoadCallback>, Bitmap>> loadedBitmaps;
    private LinkedList<Integer> texturesForDelete;

    public static TileTextureManager getInstance() {
        synchronized (lock) {
            if (instance == null) {
                instance = new TileTextureManager();
            }
        }

        return instance;
    }

    private Context context;
    private int defaultTileTexture;

    private TileTextureManager() {
        loadedBitmaps = new LinkedList<Pair<WeakReference<TextureLoadCallback>, Bitmap>>();
        texturesForDelete = new LinkedList<Integer>();
    }

    public void setContext(Context context) {
        this.context = context;
    }

    public int loadTexture(TileInfo tileInfo, TextureLoadCallback callback) {
        Loader loader = new Loader(tileInfo, callback);
        loader.setBitmapLoadCallback(this);
        loader.start();

        return defaultTileTexture;
    }

    public void initialize(GL10 gl) {
        //load default tile
        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.default_tile);

        defaultTileTexture = Utils.registerTexture(gl, bitmap);

        // Clean up
        bitmap.recycle();
    }

    public void update(GL10 gl) {
        //Удаляем старые текстуры
        synchronized (texturesForDelete) {
            while(!texturesForDelete.isEmpty()) {
                Utils.unregisterTexture(gl, texturesForDelete.pollFirst().intValue());
            }
        }

        //Грузим новые текстуры
        synchronized (loadedBitmaps) {
            int textureId;
            while (!loadedBitmaps.isEmpty()) {
                Pair<WeakReference<TextureLoadCallback>, Bitmap> pair = loadedBitmaps.pollFirst();
                TextureLoadCallback textureLoadCallback = pair.first.get();
                if (textureLoadCallback != null && pair.second != null) {
                    textureId = Utils.registerTexture(gl, pair.second);
                    textureLoadCallback.textureLoaded(textureId);
                    pair.second.recycle();
                }
            }
        }
    }

    public void unregisterTexture(int textureId) {
        if (textureId == defaultTileTexture) {
            return;
        }

        synchronized (texturesForDelete) {
            texturesForDelete.addLast(new Integer(textureId));
        }
    }

    @Override
    public void bitmapLoaded(WeakReference<TextureLoadCallback> callback, Bitmap bitmap) {
        synchronized (loadedBitmaps) {
            loadedBitmaps.addLast(new Pair<WeakReference<TextureLoadCallback>, Bitmap>(callback, bitmap));
        }
    }

    private static class Loader extends Thread {
        private WeakReference<TextureLoadCallback> callback;
        private TileInfo tileInfo;

        private BitmapLoadCallback bitmapLoadCallback;

        public Loader(TileInfo tileInfo, TextureLoadCallback callback) {
            super();
            this.tileInfo = tileInfo;
            this.callback = new WeakReference<TextureLoadCallback>(callback);
            bitmapLoadCallback = null;
        }

        public void setBitmapLoadCallback(BitmapLoadCallback bitmapLoadCallback) {
            this.bitmapLoadCallback = bitmapLoadCallback;
        }

        @Override
        public void run() {
            Bitmap bitmap = ImageLoader.loadImage("http://a.tile.openstreetmap.org/" + tileInfo.getZoom() + "/" + tileInfo.getX() + "/" + tileInfo.getY() + ".png");

            if (bitmapLoadCallback != null) {
                bitmapLoadCallback.bitmapLoaded(callback, bitmap);
            }
        }
    }


}
